
package com.tgh.utils;

import android.opengl.GLES20;
import android.util.SparseArray;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

public class GLBatch {

    public GLBatch(int mode, int vertexNum) {
        this.mPrimitiveMode = mode;
        this.mVertexNum = vertexNum;
    }

    public void end() {
        if (mVertices == null) {
            throw new RuntimeException("vertices must not be null!");
        }
        mVerticeBuffer = GLTools.makeFloatBuffer(convertListToArray(mVertices));

        if (mColors != null) {
            mColorBuffer = GLTools.makeFloatBuffer(convertListToArray(mColors));
        }
        if (mNormals != null) {
            mNormalBuffer = GLTools.makeFloatBuffer(convertListToArray(mNormals));
        }

        if (mTextures != null) {
            mTexturesBuffer = new SparseArray<FloatBuffer>();
            int size = mTextures.size();
            for (int i = 0; i < size; i++) {
                int textLayer = mTextures.keyAt(i);
                ArrayList<Float> textures = mTextures.valueAt(i);
                FloatBuffer textureBuffer = GLTools.makeFloatBuffer(convertListToArray(textures));
                mTexturesBuffer.put(textLayer, textureBuffer);
            }
        }
    }

    public void draw() {
        GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_VERTEX, 3, GLES20.GL_FLOAT,
                false, 0, mVerticeBuffer);
        GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_VERTEX);
        if (mNormalBuffer != null) {
            GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_NORMAL, 3, GLES20.GL_FLOAT,
                    false, 0, mNormalBuffer);
            GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_NORMAL);
        }
        if (mColorBuffer != null) {
            GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_COLOR, 4, GLES20.GL_FLOAT,
                    false, 0, mColorBuffer);
            GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_COLOR);
        }
        if (mTexturesBuffer != null) {
            int size = mTexturesBuffer.size();
            for (int i = 0; i < size; i++) {
                int textLayer = mTexturesBuffer.keyAt(i);
                FloatBuffer textureBuffer = mTexturesBuffer.valueAt(i);
                GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_TEXTURE0 + textLayer, 2,
                        GLES20.GL_FLOAT, false, 0, textureBuffer);
                GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_TEXTURE0 + textLayer);
            }
        }
        GLES20.glDrawArrays(mPrimitiveMode, 0, mVertexNum);
    }

    public void copyVertexData(Vector3f[] vertices) {
        copyVertexDataf(Math3D.vector3fsToArray(vertices));
    }

    public void copyVertexData(List<Vector3f> vertices) {
        copyVertexDataf(Math3D.vector3fsToArray(vertices));
    }

    public void copyVertexDataf(List<Float> vertices) {
        copyVertexDataf(convertListToArray(vertices));
    }

    public void copyVertexDataf(float[] vertices) {
        if (mVertices == null) {
            mVertices = new ArrayList<Float>();
        } else {
            mVertices.clear();
        }
        for (int i = 0; i < vertices.length; i++) {
            mVertices.add(vertices[i]);
        }
    }

    public void copyNormalData(Vector3f[] normals) {
        copyNormalDataf(Math3D.vector3fsToArray(normals));
    }

    public void copyNormalData(List<Vector3f> normals) {
        copyNormalDataf(Math3D.vector3fsToArray(normals));
    }

    public void copyNormalDataf(List<Float> normals) {
        copyNormalDataf(convertListToArray(normals));
    }

    public void copyNormalDataf(float[] normals) {
        if (mNormals == null) {
            mNormals = new ArrayList<Float>();
        } else {
            mNormals.clear();
        }
        for (int i = 0; i < normals.length; i++) {
            mNormals.add(normals[i]);
        }
    }

    public void copyColorData(Vector4f[] colors) {
        copyColorDataf(Math3D.vector4fsToArray(colors));
    }

    public void copyColorData(List<Vector4f> colors) {
        copyColorDataf(Math3D.vector4fsToArray(colors));
    }

    public void copyColorDataf(List<Float> colors) {
        copyColorDataf(convertListToArray(colors));
    }

    public void copyColorDataf(float[] colors) {
        if (mColors == null) {
            mColors = new ArrayList<Float>();
        } else {
            mColors.clear();
        }
        for (int i = 0; i < colors.length; i++) {
            mColors.add(colors[i]);
        }
    }

    public void copyTexturesData(Vector2f[] textures, int textureLayer) {
        copyTextureDataf(Math3D.vector2fsToArray(textures), textureLayer);
    }

    public void copyTexturesData(List<Vector2f> textures, int textureLayer) {
        copyTextureDataf(Math3D.vector2fsToArray(textures), textureLayer);
    }

    public void copyTextureDataf(List<Float> textures, int textureLayer) {
        copyTextureDataf(convertListToArray(textures), textureLayer);
    }

    public void copyTextureDataf(float[] textures, int textureLayer) {
        if (mTextures == null) {
            mTextures = new SparseArray<ArrayList<Float>>();
        }
        ArrayList<Float> textureBuffer = mTextures.get(textureLayer);
        if (textureBuffer == null) {
            textureBuffer = new ArrayList<Float>();
            mTextures.put(textureLayer, textureBuffer);
        } else {
            textureBuffer.clear();
        }
        for (int i = 0; i < textures.length; i++) {
            textureBuffer.add(textures[i]);
        }
    }

    public void vertex(Vector3f vect) {
        if (mVertices == null) {
            mVertices = new ArrayList<Float>();
        }
        mVertices.add(vect.x);
        mVertices.add(vect.y);
        mVertices.add(vect.z);
    }

    public void vertex(float[] vect) {
        if (mVertices == null) {
            mVertices = new ArrayList<Float>();
        }
        mVertices.add(vect[0]);
        mVertices.add(vect[1]);
        mVertices.add(vect[2]);
    }

    public void vertex(float x, float y, float z) {
        if (mVertices == null) {
            mVertices = new ArrayList<Float>();
        }
        mVertices.add(x);
        mVertices.add(y);
        mVertices.add(z);
    }

    public void normal(Vector3f normal) {
        if (mNormals == null) {
            mNormals = new ArrayList<Float>();
        }
        mNormals.add(normal.x);
        mNormals.add(normal.y);
        mNormals.add(normal.z);
    }

    public void normal(float[] normal) {
        if (mNormals == null) {
            mNormals = new ArrayList<Float>();
        }
        mNormals.add(normal[0]);
        mNormals.add(normal[1]);
        mNormals.add(normal[2]);
    }

    public void normal(float x, float y, float z) {
        if (mNormals == null) {
            mNormals = new ArrayList<Float>();
        }
        mNormals.add(x);
        mNormals.add(y);
        mNormals.add(z);
    }

    public void color(Vector4f color) {
        if (mColors == null) {
            mColors = new ArrayList<Float>();
        }
        mColors.add(color.x);
        mColors.add(color.y);
        mColors.add(color.z);
        mColors.add(color.w);
    }

    public void color(float[] color) {
        if (mColors == null) {
            mColors = new ArrayList<Float>();
        }
        mColors.add(color[0]);
        mColors.add(color[1]);
        mColors.add(color[2]);
        mColors.add(color[3]);
    }

    public void color(float r, float g, float b, float a) {
        if (mColors == null) {
            mColors = new ArrayList<Float>();
        }
        mColors.add(r);
        mColors.add(g);
        mColors.add(b);
        mColors.add(a);
    }

    public void multiTexCoord(int textLayer, float[] coord) {
        if (mTextures == null) {
            mTextures = new SparseArray<ArrayList<Float>>();
        }
        ArrayList<Float> textBuffer = mTextures.get(textLayer);
        if (textBuffer == null) {
            textBuffer = new ArrayList<Float>();
            mTextures.put(textLayer, textBuffer);
        }
        textBuffer.add(coord[0]);
        textBuffer.add(coord[1]);
    }

    public void multiTexCoord(int textLayer, Vector2f coord) {
        if (mTextures == null) {
            mTextures = new SparseArray<ArrayList<Float>>();
        }
        ArrayList<Float> textBuffer = mTextures.get(textLayer);
        if (textBuffer == null) {
            textBuffer = new ArrayList<Float>();
            mTextures.put(textLayer, textBuffer);
        }
        textBuffer.add(coord.x);
        textBuffer.add(coord.y);
    }

    public void multiTexCoord(int textLayer, float s, float t) {
        if (mTextures == null) {
            mTextures = new SparseArray<ArrayList<Float>>();
        }
        ArrayList<Float> textBuffer = mTextures.get(textLayer);
        if (textBuffer == null) {
            textBuffer = new ArrayList<Float>();
            mTextures.put(textLayer, textBuffer);
        }
        textBuffer.add(s);
        textBuffer.add(t);
    }

    private float[] convertListToArray(List<Float> list) {
        float[] array = new float[list.size()];
        for (int i = 0; i < array.length; i++) {
            array[i] = list.get(i);
        }
        return array;
    }

    private ArrayList<Float> mVertices;

    private ArrayList<Float> mNormals;

    private ArrayList<Float> mColors;

    private SparseArray<ArrayList<Float>> mTextures;

    private int mPrimitiveMode;

    private int mVertexNum;

    private FloatBuffer mVerticeBuffer;

    private SparseArray<FloatBuffer> mTexturesBuffer;

    private FloatBuffer mNormalBuffer;

    private FloatBuffer mColorBuffer;
}
